package dai.samples.shiro.config.session.dao;

import com.alibaba.fastjson.JSON;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.ValidatingSession;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * shiro提供了SessionDAO接口，可以实现自己的会话管理逻辑，
 * 比如将数据存放到redis或者mongodb中或者数据库中。
 * 这只是一个简单的demo，直接把自定义的session转换成SimpleSession，这样的话需要写的内容就很少。
 * 实际使用中可以实现下面的接口来用自己定义的SimpleSession
 * @see ValidatingSession
 */
@Repository
public class MySessionDAO extends AbstractSessionDAO {

    private static final Logger log = LoggerFactory.getLogger(MySessionDAO.class);

    @Autowired
    RedisTemplate<Serializable, Session> redisTemplate;

    private String key = "SessionCache";

    @Override
    protected Serializable doCreate(Session session) {
        ((SimpleSession)session).setId(generateSessionId(session));
        log.info("创建session： 为 {}", JSON.toJSONString(session));
        redisTemplate.boundValueOps(key + session.getId()).set(session,session.getTimeout(), TimeUnit.MILLISECONDS);
        return session.getId();
    }

    @Override
    protected Session doReadSession(Serializable serializable) {
        log.info("读取session：id 为 {}",serializable);
        Session session = redisTemplate.boundValueOps(key + serializable).get();
        return session;
    }

    @Override
    public void update(Session session) throws UnknownSessionException {
        log.info("更新session: 为 {}", JSON.toJSONString(session));
        redisTemplate.boundValueOps(key + session.getId()).set(session,session.getTimeout(), TimeUnit.MILLISECONDS);
    }

    @Override
    public void delete(Session session) {
        log.info("删除session：id 为 {}",session.getId());
        redisTemplate.delete(session.getId());
    }

    @Override
    public Collection<Session> getActiveSessions() {
        Set<Serializable> keys = redisTemplate.keys(key + "*");
        List<Session> collect = keys.stream().map(item -> redisTemplate.boundValueOps(item).get()).collect(Collectors.toList());
        return collect;
    }
}
